/*************************************************************************************
 * @Description  : LEDC举例，通过Task完成IRAM中断中的传参，本程序通过调用LED CONTROL硬件实现了一个简单的呼吸灯并在每次变换期间检测占空比。
 * @Version      : beta-1.0.1
 * @Author       : YunWuHai
 * @Date         : 2021-05-01 17:15:47
 * @LastEditors  : YunWuHai
 * @LastEditTime : 2021-05-03 00:49:29
 * @FilePath     : \ledc\main\ledc_example_main.c
 * @Copyright (C) 2021 YunWuHai. All rights reserved.
 *************************************************************************************/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/ledc.h"
#include "esp_err.h"

#define LEDC_TEST_TIMER             LEDC_TIMER_0            // 定时器
#define LEDC_TEST_SPEED_MODE        LEDC_HIGH_SPEED_MODE    // 模式
#define LEDC_TEST_GPIO              2                       // 引脚编号
#define LEDC_TEST_CHANNEL           LEDC_CHANNEL_0          // 通道
#define LEDC_TEST_FREQ              1000                    // 频率 

#define LEDC_TEST_DUTY              (2000)                  // 占空比
#define LEDC_TEST_DUTY_RESOLUTION	LEDC_TIMER_13_BIT       // 精度

#define LEDC_TEST_FADE_TIME         (500)                  // 变化时间

#define DELAY			    (LEDC_TEST_FADE_TIME + 300)    // 延时时间

static xQueueHandle testEventQueue = NULL;  // 数据队列

static void IRAM_ATTR ledc_isr_handler(void* arg)
{
    uint32_t duty = ledc_get_duty(LEDC_TEST_SPEED_MODE, LEDC_TEST_CHANNEL);
    xQueueSend(testEventQueue, &duty, (TickType_t)NULL);
}

static void ledc_task(void* arg)
{
    uint32_t duty;
    TickType_t xTaskWokenByReceive = pdFALSE;

    while(1)
    {
        if (xQueueReceive(testEventQueue, &duty, (TickType_t) &xTaskWokenByReceive)) 
        {
            printf("Duty Num:%d\n", duty);
	    }
    }
}

void app_main(void) 
{
    ledc_timer_config_t ledc_timer = {
        .duty_resolution = LEDC_TEST_DUTY_RESOLUTION,
        .freq_hz = LEDC_TEST_FREQ,
        .speed_mode = LEDC_TEST_SPEED_MODE,
        .timer_num = LEDC_TEST_TIMER,
        .clk_cfg = LEDC_AUTO_CLK
    };
    ledc_timer_config(&ledc_timer);

    ledc_channel_config_t ledc_channel = {
        .channel    = LEDC_TEST_CHANNEL,
        .duty       = 0,
        .gpio_num   = LEDC_TEST_GPIO,
        .speed_mode = LEDC_TEST_SPEED_MODE,
        .hpoint     = 0,
        .timer_sel  = LEDC_TEST_TIMER,
        .intr_type  = LEDC_INTR_FADE_END,
    };
    ledc_channel_config(&ledc_channel);

    testEventQueue = xQueueCreate(10, sizeof(uint32_t));    // 分配队列空间
    xTaskCreate(ledc_task, "ledc_task", 2048, NULL, 10, NULL);  // 创建任务

    ledc_fade_func_install(ESP_INTR_FLAG_SHARED);   // 启动
    ledc_isr_register(&ledc_isr_handler, (void *)ledc_channel.channel, ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_IRAM, NULL);    // 中断分配
    
    while(1)
    {
        printf("up!");
        ledc_set_fade_with_time(ledc_channel.speed_mode, ledc_channel.channel, LEDC_TEST_DUTY, LEDC_TEST_FADE_TIME);
        ledc_fade_start(ledc_channel.speed_mode, ledc_channel.channel, LEDC_FADE_NO_WAIT);
        vTaskDelay(DELAY / portTICK_PERIOD_MS);

        printf("down!");
        ledc_set_fade_with_time(ledc_channel.speed_mode, ledc_channel.channel, 0, LEDC_TEST_FADE_TIME);
        ledc_fade_start(ledc_channel.speed_mode, ledc_channel.channel, LEDC_FADE_NO_WAIT);
        vTaskDelay(DELAY /  portTICK_PERIOD_MS);
    }
}
